﻿using Common;
using HandyControl.Controls;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Diagnostics.Eventing.Reader;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Channels;
using System.Threading.Tasks;
using System.Windows.Markup;
using ZoneLine.Models;
using ZoneLine.Models.StationConfig;

namespace ZoneLine.Stations
{
    /// <summary>
    /// 吐片机
    /// </summary>
    public class QOP020Station : WorkStationDBase
    {
        public QOP020Station()
        {
        }

        private QOP020StationConfig _config;

        public void Init(QOP020StationConfig config)
        {
            Ip = config.Ip;
            Port = 102;
            _startAddr = config.ReadStartAddr;
            EndUpLoadCodeAddr = config.EndUploadCodeAddr;
            EndUpLoadDataAddr = config.EndUploadDataAddr;
            AllowWorkAddr = config.AllowWorkAddr;
            ProductChannelAddr = config.WorkChannelAddr;
            _readLength = 406;
            _apiUrl = config.ApiUrl;
            _config = config;
            HeartToPlcAddr = "DB55.18.0";
            Task.Run(() =>
            {
                GetStationFromMes();
            });
        }

        private async void GetStationFromMes()
        {
            while (string.IsNullOrEmpty(MesStationNo))
            {
                try
                {
                    LogWithUi(CurrentStationName + "uilog", $"开始获取工位编号");
                    long stationIdBase = 1656504687085625344;
                    var stationInfoResult = await ApiHelper.GetStaionInfo(_apiUrl);
                    LogWithUi(CurrentStationName + "uilog", $"获取工位编号信息返回" + JsonConvert.SerializeObject(stationInfoResult));
                    if (stationInfoResult.IsSuccess)
                    {
                        MesStationNo = stationInfoResult.data.list.FirstOrDefault(p => p.id == stationIdBase)?.id.ToString();
                        if (!string.IsNullOrEmpty(MesStationNo))
                        {
                            break;
                        }
                    }
                }
                catch (Exception ex)
                {
                    LogWithUi(CurrentStationName + "uilog", $"获取工位编号失败，失败原因是{ex.Message}");
                }
                Thread.Sleep(2000);
            }
        }

        private string _getStationNoStatus = "获取站点编号中";

        public string GetStationNoStatus
        {
            get { return _getStationNoStatus; }
            set => SetProperty(ref _getStationNoStatus, value);
        }

        private string _mesStationNo;

        public string MesStationNo
        {
            get { return _mesStationNo; }
            set => SetProperty(ref _mesStationNo, value);
        }

        private int _productChannel;

        /// <summary>
        /// 指定产品通道
        /// </summary>
        public int ProductChannel
        {
            get { return _productChannel; }
            set => SetProperty(ref _productChannel, value);
        }

        private string _apiUrl;

        private float _currentMesRlt = 0.0f;

        public string ProductChannelAddr { get; set; }

        private QOP020StationResult _stationResult = new QOP020StationResult();

        public QOP020StationResult StationRecordData
        { get { return _stationResult; } set => SetProperty(ref _stationResult, value); }

        protected override async void DealWithSignal(string name)
        {
            if (name == nameof(StartUploadCode))
            {
                //todo 上传了条码 这时候验证是否要工作
                if (StartUploadCode == false)
                {
                    WriteData(EndUpLoadCodeAddr, false);
                    WriteData(AllowWorkAddr, 0);
                    return;
                }
                else
                {
                    _currentMesRlt = 0.0f;
                    LogWithUi(CurrentStationName + "uilog", $"在{CurrentStationName}工位结论验证,条码信息是{StationRecordData.AbsScanCode}");
                    var validataResultTemp = Validata(CurrentStationName, StationRecordData.AbsScanCode);
                    //验证通过，开始api验证
                    var validataResult = validataResultTemp;
                    if (validataResultTemp == WorkActionEnum.StartWork && _config.EnableApi)
                    {
                        int currentCount = 0;
                        while (currentCount <= _config.ReQueryCount)
                        {
                            currentCount++;
                            //OP150
                            if (string.IsNullOrEmpty(MesStationNo))
                            {
                                LogWithUi(CurrentStationName + "uilog", $"在{CurrentStationName}工位从mes获取工位编号信息");
                                long stationIdBase = 1656504687085625344;
                                var stationInfoResult = await ApiHelper.GetStaionInfo(_apiUrl);
                                if (stationInfoResult.IsSuccess)
                                {
                                    MesStationNo = stationInfoResult.data.list.FirstOrDefault(p => p.id == stationIdBase)?.id.ToString();
                                }
                                else
                                {
                                    LogWithUi(CurrentStationName + "uilog", $"在{CurrentStationName}工位从mes获取工位编号信息失败");
                                    validataResult = WorkActionEnum.CalHErr;
                                }
                            }

                            if (!string.IsNullOrEmpty(MesStationNo))
                            {
                                try
                                {
                                    var (mesResult, calRlt, channel) = CalChannel(StationRecordData.AbsScanCode, StationRecordData.SpringCode).GetAwaiter().GetResult();
                                    _currentMesRlt = mesResult;
                                    LogWithUi(CurrentStationName + "uilog", $"计算高度成功，使用通道号信息{channel}");
                                    WriteData(ProductChannelAddr, channel);
                                    break;
                                }
                                catch (TaskCanceledException ex)
                                {
                                    LogWithUi(CurrentStationName + "uilog", $"从Mes系统获取数据失败，mes系统不返回数据");
                                    validataResult = WorkActionEnum.CalHErr;
                                }
                                catch (Exception ex)
                                {
                                    LogWithUi(CurrentStationName + "uilog", $"计算高度差失败，失败原因是{ex.Message}");
                                    validataResult = WorkActionEnum.CalHErr;
                                }
                            }
                            Thread.Sleep(1000);
                        }
                    }
                    LogWithUi(CurrentStationName + "uilog", $"在{CurrentStationName}工位结论验证,验证结论是{validataResult.ToString()}");
                    var writeToRlt = WriteWorkActionToPlc(AllowWorkAddr, validataResult);
                    if (writeToRlt)
                    {
                        LogWithUi(CurrentStationName + "uilog", $"在{CurrentStationName}向下个工位写入控制命令成功");
                    }
                    else
                    {
                        LogWithUi(CurrentStationName + "uilog", $"在{CurrentStationName}向下个工位写入控制命令失败");
                    }
                    return;
                }
            }

            if (name == nameof(StartUploadData))
            {
                if (StartUploadData)
                {
                    //todo 上传数据 这时候将数据记录到数据库中
                    var rlt = RecordData();
                    LogWithUi(CurrentStationName + "uilog", $"在{CurrentStationName}工位开始保存数据的结果是{rlt}");
                    WriteData(EndUpLoadDataAddr, rlt == 1);
                }
                else
                {
                    WriteData(EndUpLoadDataAddr, false);
                    _currentMesRlt = 0.0f;
                }
            }
        }

        protected override void DealData(byte[] content)
        {
            StationRecordData.AbsScanCode = GetPlcString(content, 26);
            StationRecordData.SpringCode = GetPlcString(content, 58);
            StationRecordData.PartType = GetPlcString(content, 90);
            StationRecordData.Result = GetPlcString(content, 102);
            StationRecordData.ShimValue = _client.ByteTransform.TransSingle(content, 114);
            StationRecordData.WorkChannel = _client.ByteTransform.TransInt16(content, 118);

            StationRecordData.ShimLeft1 = GetPlcString(content, 150);
            StationRecordData.ShimRight1 = GetPlcString(content, 182);
            StationRecordData.ShimLeft2 = GetPlcString(content, 214);
            StationRecordData.ShimRight2 = GetPlcString(content, 246);
            StationRecordData.ShimLeft3 = GetPlcString(content, 278);
            StationRecordData.ShimRight3 = GetPlcString(content, 310);
            StationRecordData.ShimLeft4 = GetPlcString(content, 342);
            StationRecordData.ShimRight4 = GetPlcString(content, 374);
            StationRecordData.SpringBatchCode = GetPlcString(content, 406);

            Logger.Log.Debug($"{_logUiChannel}，StartAddr：{_startAddr}，DealData，ReceiveData 转化前=》{string.Join(" ", content)}");
            Logger.Log.Debug($"{_logUiChannel}，StartAddr：{_startAddr}，DealData，ReceiveData 转化后=》{_client.ByteTransform.TransString(content, Encoding.ASCII)}");
            Logger.Log.Debug($"{_logUiChannel}，StartAddr：{_startAddr}，DealData，HandleData  处理后=》{JsonConvert.SerializeObject(StationRecordData)}");
        }

        protected override void DealDataCommon(byte[] content)
        {
            StationCode = GetPlcString(content, 0);

            StartUploadData = _client.ByteTransform.TransBool(content, 12 * 8 + 2);
            StartUploadCode = _client.ByteTransform.TransBool(content, 12 * 8 + 1);

            HeartToPlc = _client.ByteTransform.TransBool(content, 18 * 8);

            EndUpLoadData = _client.ByteTransform.TransBool(content, 18 * 8 + 1);
            EndUpLoadCode = _client.ByteTransform.TransBool(content, 18 * 8 + 1); ;
            AllowWork = _client.ByteTransform.TransInt16(content, 20);
            ProductChannel = _client.ByteTransform.TransInt16(content, 22);
        }

        protected override int RecordData()
        {
            LogWithUi(CurrentStationName + "uilog", $"在{CurrentStationName}工位开始保存数据");
            var result = new QOP020StationResult()
            {
                AbsScanCode = StationRecordData.AbsScanCode,
                StationCode = this.StationCode,
                Result = StationRecordData.Result,
                ShimValue = StationRecordData.ShimValue,
                PartType = StationRecordData.PartType,
                WorkChannel = StationRecordData.WorkChannel,
                SpringCode = StationRecordData.SpringCode,
                AirSpring = _currentMesRlt,
                SpringBatchCode = StationRecordData.SpringBatchCode,
                ShimLeft1 = StationRecordData.ShimLeft1,
                ShimLeft2 = StationRecordData.ShimLeft2,
                ShimLeft3 = StationRecordData.ShimLeft3,
                ShimLeft4 = StationRecordData.ShimLeft4,
                ShimRight1 = StationRecordData.ShimRight1,
                ShimRight2 = StationRecordData.ShimRight2,
                ShimRight3 = StationRecordData.ShimRight3,
                ShimRight4 = StationRecordData.ShimRight4,
            };
            var writeRlt = false;
            if (_dal.CheckExist<QOP020StationResult>(p => p.AbsScanCode == result.AbsScanCode))
            {
                var beforeRlt = _dal.GetModel<QOP020StationResult>(p => p.AbsScanCode == result.AbsScanCode);
                result.Id = beforeRlt.Id;
                writeRlt = _dal.UpdateModelSuper<QOP020StationResult>(p => p.AbsScanCode == result.AbsScanCode, result);
            }
            else
            {
                writeRlt = _dal.AddModel(result);
            }
            return writeRlt ? 1 : 2;
        }

        /// <summary>
        /// </summary>
        /// <param name="absCode">工件码</param>
        /// <param name="springCode">弹簧力</param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public async Task<(float, float, short)> CalChannel(string absCode, string springCode)
        {
            //弹簧设计载荷: a，气体反弹力: b; 高度偏差: H
            if (string.IsNullOrEmpty(MesStationNo))
            {
                throw new Exception("系统没有获取到工位编号，不能计算");
            }
            float springValue = default;
            if (!float.TryParse(springCode, out springValue))
            {
                throw new Exception("弹簧设计载荷转换异常，不能计算");
            }

            LogWithUi(CurrentStationName + "uilog", $"在{CurrentStationName}工位从mes获取弹簧力信息");
            var queryStr = $"{{\"Body\":\"{{stationId:\\\"{MesStationNo}\\\",masterCode:\\\"{absCode}\\\"}}\"}}";
            LogWithUi(CurrentStationName + "uilog", $"在{CurrentStationName}工位发送{queryStr}数据到mes");
            var (stationData, apiRlt) = await ApiHelper.GetStationData(queryStr, _apiUrl);
            LogWithUi(CurrentStationName + "uilog", $"在{CurrentStationName}mes工位返回信息是:{apiRlt}");
            if (stationData.IsSuccess)
            {
                if (stationData.data != null)
                {
                    LogWithUi(CurrentStationName + "uilog", $"在{CurrentStationName}工位获取弹簧力信息成功");
                    var data = stationData.data.FirstOrDefault(p => p.parameterConfigName == "反弹力")?.parameterValue;
                    LogWithUi(CurrentStationName + "uilog", $"在{CurrentStationName}工位获取弹簧力信息是{data}");
                    if (float.TryParse(data, out float result))
                    {
                        float H = (float)((springValue - 7798.5f) / 53 + (result - 125) / 53 + 3.5);
                        short channel = 0;
                        if (0 <= H && H <= 1.4)
                        {
                            //使用通道1
                            channel = 1;
                        }
                        else if (1.4 < H && H <= 2.8)
                        {
                            //使用通道2
                            channel = 2;
                        }
                        else if (2.8 < H && H <= 4.2)
                        {
                            //使用通道3
                            channel = 3;
                        }
                        else if (4.2 < H && H <= 5.6)
                        {
                            //使用通道4
                            channel = 4;
                        }
                        else if (5.6 < H && H <= 7)
                        {
                            //使用通道5
                            channel = 5;
                        }
                        else
                        {
                            throw new Exception($"高度偏差数据计算结果是{H},超限报警");
                        }
                        return (result, H, channel);
                    }
                    else
                    {
                        throw new Exception("获取到的弹簧力信息不正确不能转换");
                    }
                }
                else
                {
                    LogWithUi(CurrentStationName + "uilog", $"在{CurrentStationName}工位获取弹簧力信息为空，请检查");
                    throw new Exception("获取到的弹簧力数据为空");
                }
            }
            else
            {
                LogWithUi(CurrentStationName + "uilog", $"在{CurrentStationName}工位获取弹簧力信息失败");
                throw new Exception("获取弹簧力信息失败");
            }
        }
    }
}